//
//  NSKMoya.swift
//  NSKMoya
//
//  Created by Fineland on 2021/3/8.
//

import Moya

enum NSKResponseCode: Int {
    
    //1000-成功；1001-用户会话失效；1002-source参数错误；1003-店铺不存在；9999-失败；
    case success        = 0
    case sessionFailure = 1001
    case paramsError    = 1002
    case shopNotExist   = 1003
    case failure        = 9999
    case unknow
}

enum NSKMoyaAPI {
    
    //注册
    case register(params: Any)
    //登录
    case login(params: Any)
    /// 开单
    case createOrder(params: Any)
    /// 开单
    case creCar(params: Any)
//    wx/company/search?kw=%E9%83%91%E5%B7%9E&p=1
    case searchWL(params: Any)
    
    //查询店铺
    case store(params: Any)
    //店铺统计信息
    case statistics(params: Any)
    //上传店铺logo
    case uploadLogo(img: UIImage)
    //店铺列表
    case storeList(params: Any)
    //新增店铺
    case saveStore(params: Any)
    //修改店铺信息
    case updateStore(params: Any)
    //删除店铺
    case deleteStore(params: Any)
    //图片上传
    case upload(imgs: Array<UIImage>)
    //设置默认店铺
    case defaultS(params: Any)
   
   
}

// MARK: -

extension NSKMoyaAPI: TargetType {
    
    var baseURL: URL {
        switch self {
        case .searchWL:
            return URL(string: NSKHost.shared.root3Url)!
        default:
            return URL(string: NSKHost.shared.url)!
        }
        
    }
    
    var path: String {
        
        switch self {
        case .register:
            return "system/user/register"
        case .login:
            return "mTransfer/Login"
        case .store:
            return "system/store/getStore"
        case .statistics:
            return "system/store/getStoreStatistics"
        case .storeList:
            return "system/store/getStoreList"
        case .saveStore:
            return "system/store/saveStore"
        case .updateStore:
            return "system/store/updateStore"
        case .deleteStore:
            return "system/store/deleteStor"
        case .upload:
            return "file/upload"
        case .uploadLogo:
            return "file/uploadStoreLogo"
        case .defaultS:
            return "system/store/setDefaultStore"
        case .createOrder:
            return "mFinance/creatOrderListForCompanyTwo"
        case .creCar:
//            https://www.56114.net/mFinance/creatListInfoForThreeCompany
            return "mFinance/creatListInfoForThreeCompany"
        case .searchWL:
            return ""
        default:
            break
        }
    }
    
    var method: Moya.Method {
        
        switch self {
        case .store, .statistics, .storeList:
            return .get
        default:
            break
        }
        return .post
    }
    
    var task: Task {
        
        switch self {
        case .register(let params),
             .login(let params),
             .saveStore(let params),
             .updateStore(let params),
             .deleteStore(let params),
             .defaultS(let params),
             .createOrder(let params),
             .creCar(let params):
            var param = params as! Dictionary<String, Any>
            if let loginObj = NSKUserInfo.shared.loginUser {
                param["taken"] = loginObj.token
            }
            return Task.requestData(rqdata(param))
        case .upload(let imgs):
            return uploadTask(imgs)
        case .uploadLogo(let img):
            return uploadTask([img])
        default:
            break
        }
        return Task.requestParameters(parameters: [:], encoding: URLEncoding.default)
    }
    
    var sampleData: Data {
        
        return "".data(using: .utf8)!
    }
    
    var headers: [String : String]? {
        
        //结果
        var tempData: Dictionary<String, String> = ["Content-type": "application/json"]
        //是否为空？
        if let loginObj = NSKUserInfo.shared.loginUser {
            tempData["token"] = loginObj.token
//            if let storeObj = loginObj.store {
//                tempData["storeId"] = "\(storeObj.id)"
//            }
        }
        //返回
        return tempData
    }
    
    private func rqdata(_ p: Any) -> Data {
        
        do {
            //结果
            let tempData = try JSONSerialization.data(withJSONObject: p, options: [])
            let reqString = String(bytes: tempData, encoding: .utf8)!
            #if DEBUG
            print("发送内容 = \(reqString)")
            #endif
            //返回
            return tempData
        } catch {
            print("Object->JsonData错误...")
        }
        //返回
        return Data()
    }
    
    private func uploadTask(_ imgs: Array<UIImage>) -> Task {
        
        //结果
        var multipartObjs: Array<Moya.MultipartFormData> = []
        for img in imgs {
            guard let imgData = img.jpegData(compressionQuality: 0.1) else {
                continue
            }
            let formData = MultipartFormData(provider: .data(imgData), name: "file", fileName: "img.jpg",mimeType: "image/jpeg")
            multipartObjs.append(formData)
        }
        return Task.uploadMultipart(multipartObjs)
    }
}

// MARK: -

class NSKHost {
    /// 单例实例
    static let shared = NSKHost()
    /// 重写init 禁止外部初始化
    private init(){}
    
    //注：第1个地址的"前面加上“/*”为测试环境，否则为正式环境
    //当前URL
    private let rootUrl = "https://www.56114.net/"
//    /*"http://community.fineland.cn"//正式环境*/"http://120.79.166.184"//测试环境
    
    let root2Url = "https://zz.56114.com/"
    
    /// 查单接口
    let root3Url = "http://track.56114.com/"
    var url: String {
        
//        return NSKHost.shared.rootUrl + ":8080" + "/"
        return NSKHost.shared.rootUrl
    }
    
    var imageUrl: String {
        
        return NSKHost.shared.rootUrl
    }
}

// MARK: -

class NSKMoyaRequstAPI: NSObject {
    
    //请求对象
    private var providerObj: MoyaProvider<NSKMoyaAPI>!
    //当前target对象
    private var targetObj: NSKMoyaAPI!
    
    //是否静默错误消息？
    var isSilenceError: Bool = false

    //回调
    typealias MoyaSuccess = (_ resObj: Any?) -> Void
    typealias MoyaFailure = (_ cde: NSKResponseCode, _ msg: String) -> Void
    private var success: MoyaSuccess!
    private var failure: MoyaFailure?
    
    func requestTarget(_ target: NSKMoyaAPI, with success: @escaping MoyaSuccess, failure: MoyaFailure? = .none) -> Void {
        
        //保存
        self.success = success
        self.failure = failure
        self.targetObj = target
        //是否为空？
        if nil == providerObj {
           //等待
           let activityPlugin = NetworkActivityPlugin { [weak self] (changeType: NetworkActivityChangeType, target: TargetType) in
               self?.waitting(changeType)
           }
           //设置请求超时时间
           let timeoutClosure = { (endpoint: Endpoint, done: @escaping MoyaProvider<NSKMoyaAPI>.RequestResultClosure) in
               do{
                   var request = try endpoint.urlRequest()
                   request.timeoutInterval = 30
                   done(.success(request))
               } catch {
                   print("超时设置异常...")
               }
           }
           //初始化请求对象
           providerObj = MoyaProvider<NSKMoyaAPI>(requestClosure: timeoutClosure, plugins: [activityPlugin])
        }
        //请求
        providerObj.request(target) { [weak self] (result) in
           self?.responseObject(result)
        }
    }
    
    func cancle() -> Void {
        
        //是否为空？
        if nil != providerObj && nil != targetObj {
            //取消请求
            providerObj.cancelCompletion({ (result: Result<Moya.Response, Moya.MoyaError>) in
                #if DEBUG
                print("取消请求...")
                #endif
            }, target: targetObj)
        }
    }
    
    private func waitting(_ changeType: NetworkActivityChangeType) -> Void {
        
        
    }
    
    private func responseObject(_ result: Result<Moya.Response, Moya.MoyaError>) -> Void {
        
        //返回值
        var resultVal: (cde: NSKResponseCode, msg: String)!
        var data: Any?
        switch result {
        case .success(let response):
            do {
                #if DEBUG
                let resString = String(bytes: response.data, encoding: .utf8)!
                print("返回内容 = \(resString)")
                #endif
                let resObj = try response.mapJSON() as! [String: Any]
                let cdeVal = NSKResponseCode(rawValue: resObj["return_code"] as! Int) ?? .unknow
                let msgVal = resObj["return_message"] as? String ?? "未知异常"
                resultVal = (cdeVal, msgVal)
                data = resObj["data"]
            } catch {
                resultVal = (.paramsError, "参数解析异常")
                #if DEBUG
                print(error)
                #endif
            }
        case .failure(let error):
            resultVal = (.failure, "未能连接到服务器")
            #if DEBUG
            print(error)
            #endif
        }
        //请求结果
        requestResult(resultVal.cde, msg: resultVal.msg, data: data)
    }
    
    private func requestResult(_ code: NSKResponseCode, msg: String, data: Any?) -> Void {
        
        //请求结果
        switch code {
        case .success:
            if let tempClosure = self.success {
                tempClosure(data)
            }
        default:
            //是否要提示错误信息？
            if true != isSilenceError { UIKToastView.showText(msg) }
            //回调是否为空？
            if let tempClosure = self.failure {
                tempClosure(code, msg)
            }
        }
    }
}

// MARK: -

private struct AssociatedKey {
    
    //请求等待
    static var HTTP_REQUEST: String = "Http_Request_Object"
}

// MARK: -

extension UIViewController {
    
    //请求对象
    private var request: NSKMoyaRequstAPI? {

        get {
            return objc_getAssociatedObject(self, &AssociatedKey.HTTP_REQUEST) as? NSKMoyaRequstAPI
        }
        set {
            objc_setAssociatedObject(self, &AssociatedKey.HTTP_REQUEST, newValue, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
        }
    }
    
    var requestObj: NSKMoyaRequstAPI {
        
        //是否为空？
        if let tempObj = self.request {
            return tempObj
        }
        //创建
        let tempObj: NSKMoyaRequstAPI = NSKMoyaRequstAPI()
        self.request = tempObj
        return tempObj
    }
}
